`include "defines.v"

module Hazard_Detection (
    input  wire [`REGFILE_ADDR_LEN-1:0] rs1_addr,
    input  wire [`REGFILE_ADDR_LEN-1:0] rs2_addr,
    input  wire [`REGFILE_ADDR_LEN-1:0] rd_addr_ex,
    input  wire [`REGFILE_ADDR_LEN-1:0] rd_addr_mem,
    input  wire                         rd_w_en_ex,
    input  wire                         csr_w_en_ex,
    input  wire                         rd_w_src_ex,
    input  wire                         rd_w_src_mem,
    input  wire                         mem_stall_req,
    input  wire                         inst_fencei,
    input  wire                         inst_wfi,
    output wire [3:0]                   stall,

    input  wire                         inst_jump_or_branch_taken_flag,
    input  wire                         exception_jump_flag,
    output wire                         flush,
    output wire                         bubble
);
    //----------Pipeline Stall Mechanism----------//
    wire load_use_stall_ex;
    wire load_use_stall_mem;
    wire csr_to_regfile_data_hazard;

    assign load_use_stall_ex  = (rs1_addr == rd_addr_ex  || rs2_addr == rd_addr_ex)  && (|rd_addr_ex)  && rd_w_src_ex;
    assign load_use_stall_mem = (rs1_addr == rd_addr_mem || rs2_addr == rd_addr_mem) && (|rd_addr_mem) && rd_w_src_mem;
    assign csr_to_regfile_data_hazard = rd_w_en_ex && (|rd_addr_ex) && (~rd_w_src_ex) && csr_w_en_ex && (rd_addr_ex == rs1_addr || rd_addr_ex == rs2_addr);

    assign stall[3] = mem_stall_req;
    assign stall[2] = mem_stall_req;
    assign stall[1] = mem_stall_req;
    assign stall[0] = mem_stall_req | bubble & ~inst_fencei;

    //----------Pipeline Flush Mechanism----------//
    assign bubble = inst_fencei | inst_wfi | csr_to_regfile_data_hazard | load_use_stall_ex | load_use_stall_mem;
    assign flush = inst_jump_or_branch_taken_flag | exception_jump_flag;

endmodule